from v5.Pipeline import DefaultPipeline
from v5.PageProcessor import DefaultPageProcessor
from v5.ExceptionHandler import DefaultExceptionHandler
from v5.Downloader import DefaultDownloader
from v5.Exception import SpiderBaseException
import sys


class SpiderModule(object):
    def __init__(self,
                 sock_puppet,
                 page_processor_class=None,
                 pipeline_class=None,
                 exception_handler_class=None,
                 downloader_class=None
                 ):
        self.page_processor_class = page_processor_class
        self.pipeline_class = pipeline_class
        self.exception_handler_class = exception_handler_class
        self.downloader_class = downloader_class
        self.page_processor_object = page_processor_class()\
            if page_processor_class is not None else DefaultPageProcessor()
        self.pipeline_object = pipeline_class()\
            if pipeline_class is not None else DefaultPipeline()
        self.exception_handler_object = exception_handler_class()\
            if exception_handler_class is not None else DefaultExceptionHandler()
        self.downloader_object = downloader_class()\
            if downloader_class is not None else DefaultDownloader()
        self.sock_puppet = sock_puppet
        self.request_items = []

    def __deepcopy__(self, memodict={}):
        new_module = SpiderModule(
                                  self.sock_puppet,
                                  self.page_processor_class,
                                  self.pipeline_class,
                                  self.exception_handler_class,
                                  self.downloader_class
                                  )
        return new_module

    def execute(self, page):
        try:
            self.download(page, self.sock_puppet)
            self.page_process(page)
            self.pipeline(page)
        except Exception as e:
            tb = sys.exc_info()[2]
            exception = SpiderBaseException(page, e).with_traceback(tb)
            self.exception_handler(exception, self.sock_puppet, self)

    def download(self, page, sock_puppet):
        return self.downloader_object.download(page, sock_puppet)

    def page_process(self, page):
        self.page_processor_object.process(page)

    def pipeline(self, page):
        self.pipeline_object.process(page)

    def exception_handler(self, exception, sock_puppet, spider_module):
        self.exception_handler_object.handler(exception, sock_puppet, spider_module)
